﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Xml;
using System.Text;
using Gollie.WebCache;

namespace Gollie
{
	public class PageConfigurator : CacheFileDependency
	{
		private static string cacheName = "data_pageconfig";
		private static string buildNumber = "?b=" + ConfigAppSettings.BuildNumber;
		private Dictionary<string, PageConfig> pages = new Dictionary<string, PageConfig>();
		
		public PageConfigurator()
			: base(HttpContext.Current.Server.MapPath("/App_Data/PageConfig.xml"))
		{
			this.ReadPageConfig();
		}

		public static PageConfigurator GetInstance()
		{
			return DataCache.GetCacheableObject<PageConfigurator>(cacheName);
		}

		public PageConfig this[string page]
		{
			get
			{
				PageConfig pc;
				this.pages.TryGetValue(page, out pc);
				return pc;
			}
		}

		private void ReadPageConfig()
		{
			XmlDocument doc = new XmlDocument();

			doc.Load(this.DependencyPath);

			XmlNodeList nodes = doc.SelectNodes("/gollie/page");

			if (nodes != null)
			{
				foreach (XmlNode node in nodes)
				{
					this.ReadPageNode(node);
				}
			}
		}

		private void ReadPageNode(XmlNode pageNode)
		{
			StringBuilder strJS = this.InitJS();
			StringBuilder strCss = this.InitCSS();
			StringBuilder strPreload = new StringBuilder();
			StringBuilder strMeta = new StringBuilder();
			StringBuilder strTitle = new StringBuilder();

			foreach (XmlNode node in pageNode.ChildNodes)
			{
				switch (node.Name)
				{
					case "script": this.ReadJSNode(node, strJS); break;
					case "css": this.ReadCSSNode(node, strCss); break;
					case "meta": this.ReadMetaNode(node, strMeta); break;
					case "title": this.ReadTitleNode(node, strTitle); break;
					case "preload": this.ReadPreloadNode(node, strPreload); break;
				}
			}

			if (strTitle.Length == 0)
				strTitle.Append("<title>Gollie</title>");

			XmlAttribute attr = pageNode.Attributes["name"];
			if (attr == null)
				throw new Exception("Page not configured");

			string name = attr.Value;

			var pageConfig = new PageConfig() { PageName = name, PreloadHtml = strPreload.ToString(), CSSHtml = strCss.ToString(), JSHtml = strJS.ToString(), MetaHtml = strMeta.ToString(), TitleHtml = strTitle.ToString() };

			this.pages[pageConfig.PageName] = pageConfig;
		}

		private StringBuilder InitCSS()
		{
			StringBuilder str = new StringBuilder(1024);

			IEnumerable<KeyValuePair<string, string>> autoCssIncludes = ConfigAppSettings.Instance.GetAutoCSSIncludes();
			foreach (var kvp in autoCssIncludes)
			{
				str.Append("<link rel=\"stylesheet\" href=\"");
				str.Append(kvp.Value);
				str.Append("\"/>");
			}

			return str;
		}

		private StringBuilder InitJS()
		{
			StringBuilder str = new StringBuilder(1024);

			IEnumerable<KeyValuePair<string, string>> autoJSIncludes = ConfigAppSettings.Instance.GetAutoJSIncludes();
			foreach (var kvp in autoJSIncludes)
			{
				str.Append("<script src=\"");
				str.Append(kvp.Value);
				str.Append("\"></script>");
			}

			return str;
		}

		private void ReadPreloadNode(XmlNode node, StringBuilder str)
		{
			str.Append("<script>var ia=[");

			XmlNodeList nodes = node.SelectNodes("image");
			foreach (XmlNode imageNode in nodes)
			{
				XmlAttribute attr = imageNode.Attributes["src"];
				if (attr != null)
				{
					str.Append("\'"); str.Append(attr.Value); str.Append("\',");
				}
			}
			str[str.Length - 1] = ']';
			str.Append(";for(var i=0;i<ia.length;i++){var ti=new Image(); ti.src=ia[i];}</script>");
		}

		private void ReadJSNode(XmlNode node, StringBuilder str)
		{
			str.Append("<script src=\"");
			str.Append(node.Attributes["src"].Value);
			str.Append(buildNumber);
			str.Append("\"></script>");
		}

		private void ReadCSSNode(XmlNode node, StringBuilder str)
		{
			str.Append("<link rel=\"stylesheet\" type=\"text/css\" href=\"");
			str.Append(node.Attributes["src"].Value);
			str.Append(buildNumber);
			str.Append("\"/>");
		}

		private void ReadMetaNode(XmlNode node, StringBuilder str)
		{
			str.Append(node.OuterXml);
		}

		private void ReadTitleNode(XmlNode node, StringBuilder str)
		{
			str.Append(node.OuterXml);
		}
	}

	public class PageConfig
	{
		public string PageName;
		public string PreloadHtml;
		public string JSHtml;
		public string CSSHtml;
		public string MetaHtml;
		public string TitleHtml;
	}
}